package com.qqt.csr.web.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.utils.JsonUtil;
import com.qqt.csr.common.utils.ServiceAssert;
import com.qqt.csr.im.dto.ConversationDTO;
import com.qqt.csr.im.dto.SendSystemMessageDTO;
import com.qqt.csr.im.entity.Account;
import com.qqt.csr.im.entity.Conversation;
import com.qqt.csr.im.entity.RoomMember;
import com.qqt.csr.im.enums.ConversationStateEnum;
import com.qqt.csr.im.service.AccountService;
import com.qqt.csr.im.service.RoomMemberService;
import com.qqt.csr.im.service.mongo.ConversationService;
import com.qqt.csr.im.service.mongo.MessageService;
import com.qqt.csr.route.service.ConversationStatService;
import com.qqt.csr.route.service.CsReceptionLimitService;
import com.qqt.csr.workbench.entity.SkillSetConfig;
import com.qqt.csr.workbench.service.SkillSetConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ClosingConversationService {
    @Autowired
    private ConversationService conversationService;
    @Autowired
    private CsReceptionLimitService csReceptionLimitService;
    @Autowired
    private ArchiveEventMqProducerService archiveEventMqProducerService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private RoomMemberService roomMemberService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private SkillSetConfigService skillSetConfigService;
    @Autowired
    private ConversationStatService conversationStatService;
    @Autowired
    private ImAccountService imAccountService;

    /**
     * 结束会话
     *
     * @param conversationId
     * @param csId
     */
    public void closeConversation(String conversationId, Long csId) {
        Conversation conversation = conversationService.getById(conversationId);
        if (conversation == null || ConversationStateEnum.END.equals(conversation.getState())) {
            return;
        }

        JSONObject conversationExt = Optional.ofNullable(JsonUtil.toObject(conversation.getExt(), JSONObject.class)).orElseGet(JSONObject::new);

        // 客服im账户信息
        String csImUserId = imAccountService.buildCsImUserId(csId);
        Account csAccount = null;
        // 访客im账户信息
        Account vistorAccount = null;
        if (StringUtils.isNotBlank(conversation.getRoomId())) {
            List<RoomMember> roomMemberList = roomMemberService.queryMemberListBy(Long.parseLong(conversation.getRoomId()));
            List<Long> accountIdList = roomMemberList.stream().map(RoomMember::getAccountId).distinct().collect(Collectors.toList());
            Map<Long, Account> accountMap = accountService.getMapByIds(accountIdList);
            csAccount = accountMap.values().stream().filter(a -> a.getAccountUserId().equals(csImUserId)).findFirst().orElse(null);
            vistorAccount = accountMap.get(Long.parseLong(conversation.getInitiatorId()));
        } else {
            String channelId = conversationExt.getString("channelId");
            String visitorImUserId = imAccountService.buildUserImUserId(channelId, conversation.getInitiatorId());
            Map<String, Account> accountMap = accountService.getMapByUserIds(Lists.newArrayList(csImUserId, visitorImUserId));
            csAccount = accountMap.get(csImUserId);
            vistorAccount = accountMap.get(visitorImUserId);
        }

        if (csId != null && csId > 0L) {
            ServiceAssert.notNull(csAccount, StatusCode.Common.ILLEGAL.getCode(), "非当前会话处理人，关闭失败！");
        }

        // 结束会话
        conversationService.end(conversationId);
        // 释放客服进线被占用的访客名额
        csReceptionLimitService.release(csId, 1);
        // 推送系统消息结束会话提示
        pushClosedConversationSystemMsg(conversation, conversationExt, vistorAccount, csAccount);
        // 推送会话结束通知到客服工作台
        conversationService.pushCloseConversationEvent(csAccount, conversation);
        // 发送会话归档事件
        archiveEventMqProducerService.sendConversationArchiveEvent(Lists.newArrayList(conversation.getId()));
        // 统计会话时长，用于坐席调度，优化为可通过队列异步化
        conversationStatService.increaseConversationTime(conversation);
    }

    /**
     * 结束客服所有会话，并推送会话结束提醒
     *
     * @param csId
     */
    public void closeAllConversation(Long csId) {
        String csImUserId = imAccountService.buildCsImUserId(csId);
        List<ConversationDTO> conversationList = conversationService.queryConversationListBy(csImUserId, ConversationStateEnum.NORMAL, 0);
        if (CollectionUtils.isEmpty(conversationList)) {
            return;
        }

        Account csAccount = conversationList.get(0).getRoomMemberList().stream()
                .filter(rm -> rm.getAccountUserId().equals(csImUserId))
                .findFirst().orElse(null);
        if (csAccount == null) {
            return;
        }

        List<String> conversatoinIdList = conversationList.stream().map(ConversationDTO::getId).collect(Collectors.toList());
        // 结束会话
        conversationService.end(conversatoinIdList);
        // 释放客服进线被占用的访客名额
        csReceptionLimitService.release(csId, conversationList.size());
        // 推送系统消息结束会话提示
        pushClosedConversationSystemMsg(conversationList);
        // 推送会话结束通知到客服工作台
        conversationService.pushCloseConversationEvent(csAccount, conversationList);
        // 发送会话归档事件
        archiveEventMqProducerService.sendConversationArchiveEvent(conversatoinIdList);
        // 统计会话时长，用于坐席调度，优化为可通过队列异步化
        List<Conversation> cList = conversationList.stream().map(cdto -> Conversation.builder().id(cdto.getId()).ext(cdto.getExt())
                        .startTime(DateUtil.formatDateTime(cdto.getStartTime())).endTime(DateUtil.formatDateTime(cdto.getEndTime())).build())
                .collect(Collectors.toList());
        conversationStatService.increaseConversationTime(cList);
    }

    private void pushClosedConversationSystemMsg(Conversation conversation, JSONObject conversationExt,
                                                 Account visitorAccount, Account csAccount) {
        SkillSetConfig skillSetConfig = skillSetConfigService.queryBySkillSetId(conversationExt.getLong("skillSetId"));

        String todayStr = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN) + "&nbsp;&nbsp;&nbsp;";
        String endTip = todayStr + Optional.ofNullable(skillSetConfig).map(SkillSetConfig::getEndSessionTip).orElse(StringUtils.EMPTY);
        // 与前端约定，系统消息扩展字段带有 systemMsgType=1 的，表示会话结束
        JSONObject systemMsgExt = new JSONObject();
        systemMsgExt.put("systemMsgType", "1");
        String systemMsgExtStr = systemMsgExt.toJSONString();

        List<SendSystemMessageDTO> sendSystemMessageList = new ArrayList<>();
        Map<String, Account> accountMap = new HashMap<>();
        if (visitorAccount != null) {
            sendSystemMessageList.add(SendSystemMessageDTO.of(visitorAccount.getAccountUserId(), conversation.getId(), endTip, systemMsgExtStr, conversation.getRoomId()));
            accountMap.put(visitorAccount.getAccountUserId(), visitorAccount);
        }
        if (csAccount != null) {
            sendSystemMessageList.add(SendSystemMessageDTO.of(csAccount.getAccountUserId(), conversation.getId(), endTip, systemMsgExtStr, conversation.getRoomId()));
            accountMap.put(csAccount.getAccountUserId(), csAccount);
        }

        messageService.sendSystemMsg(sendSystemMessageList, accountMap);
    }

    private void pushClosedConversationSystemMsg(List<ConversationDTO> conversationList) {
        // 查询技能组配置，获取结束提示信息
        Map<String, Long> conversationSkillConfigMap = conversationList.stream()
                .map(c -> {
                    JSONObject ext = JsonUtil.toObject(c.getExt(), JSONObject.class);
                    if (ext == null) {
                        return null;
                    }
                    ext.put("cId", c.getId());
                    return ext;
                }).filter(Objects::nonNull)
                .collect(Collectors.toMap(ext -> ext.getString("cId"), v -> v.getLong("skillSetId"), (o, n) -> o));
        Map<Long, SkillSetConfig> skillSetConfigMap = skillSetConfigService.queryBySkillSetId(conversationSkillConfigMap.values().stream().distinct().collect(Collectors.toList()));

        String todayStr = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN) + "&nbsp;&nbsp;&nbsp;";

        // 与前端约定，系统消息扩展字段带有 systemMsgType=1 的，表示会话结束
        JSONObject systemMsgExt = new JSONObject();
        systemMsgExt.put("systemMsgType", "1");
        String systemMsgExtStr = systemMsgExt.toJSONString();

        Map<String, Account> accountMap = new HashMap<>();
        List<SendSystemMessageDTO> sendSystemMessageList = new ArrayList<>();
        conversationList.forEach(conversationVO -> {
            String endTip = Optional.ofNullable(conversationSkillConfigMap.get(conversationVO.getId()))
                    .map(skillSetConfigMap::get)
                    .map(SkillSetConfig::getEndSessionTip)
                    .map(tip -> todayStr + tip)
                    .orElse(StringUtils.EMPTY);

            conversationVO.getRoomMemberList().forEach(account -> {
                sendSystemMessageList.add(SendSystemMessageDTO.of(account.getAccountUserId(), conversationVO.getId(), endTip, systemMsgExtStr, conversationVO.getRoomId().toString()));
                accountMap.put(account.getAccountUserId(), account);
            });
        });
        messageService.sendSystemMsg(sendSystemMessageList, accountMap);
    }
}
